package cn.mjnxin.iot.base.domain;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

/**
 * 新接口: 数据单元.<br/>
 * 递归型，通用数据表示结构，类json格式
 *
 * @author CLG 2023年10月10日
 * @version V1.0.0
 */
public class Data
{
    /**
     * 数据类型.<br/>
     */
    public enum DataType
    {
        /**
         * 简单类型
         */
        PLAIN,
        /**
         * 复合类型
         */
        COMPOSITE,
        /**
         * 列表
         */
        LIST;
    }

    private DataType dataType = DataType.PLAIN;

    /**
     * 键
     */
    private final String key;

    // 从数据使用上来讲，一下三类数据只能同时存在一个
    /**
     * 值
     */
    private Object value;

    /**
     * 列表数据<br/>
     * 列表数据里面的结构需要保持同构，相当于多个同构的复合结构，返回列表一项时，会使用新的Data包装
     */
    private List<Map<String, Data>> subList = null;

    /**
     * 复合数据
     */
    private Map<String, Data> subMap = null;

    public Data(String key)
    {
        this.key = key;
    }

    public Data(String key, Object data)
    {
        this.key = key;
        this.value = data;
        this.dataType = DataType.PLAIN;
    }

    public Data(String key, Map<String, Data> datas)
    {
        this.key = key;
        this.subMap = datas;
        this.dataType = DataType.COMPOSITE;
    }

    public Data(String key, Data... datas)
    {
        this.key = key;
        this.addSub(datas);
        this.dataType = DataType.COMPOSITE;
    }

    public void setValue(Object value)
    {
        this.value = value;
    }

    public DataType dataType()
    {
        return this.dataType;
    }

    public void addSub(String key, Object value)
    {
        this.addSub(new Data(key, value));
    }

    public void addSub(Map<String, Object> values)
    {
        if (values == null || values.isEmpty())
        {
            return;
        }

        if (this.subMap == null)
        {
            this.subMap = new HashMap<String, Data>(4);
        }

        java.util.Iterator<Entry<String, Object>> itr = values.entrySet().iterator();
        for (; itr.hasNext();)
        {
            Entry<String, Object> entry = itr.next();
            this.subMap.put(entry.getKey(), new Data(entry.getKey(), entry.getValue()));
        }
        this.dataType = DataType.COMPOSITE;
    }

    public void addSub(Data... datas)
    {
        if (datas.length == 0)
        {
            return;
        }

        if (this.subMap == null)
        {
            this.subMap = new HashMap<String, Data>(4);
        }

        for (Data data : datas)
        {
            this.subMap.put(data.key(), data);
        }
        this.dataType = DataType.COMPOSITE;
    }

    public String key()
    {
        return this.key;
    }

    public Object value()
    {
        return this.value;
    }

    public List<Map<String, Data>> getSubList()
    {
        if (this.subList == null)
        {
            return Collections.emptyList();
        }
        return this.subList;
    }

    public List<Map<String, Data>> unmodifiableSubList()
    {
        if (this.subList == null)
        {
            return Collections.emptyList();
        }
        return Collections.unmodifiableList(this.getSubList());
    }

    public Map<String, Data> getMap()
    {
        if (this.subMap == null)
        {
            return Collections.emptyMap();
        }
        return this.subMap;
    }

    public Data getMapItem(String key)
    {
        if (this.subMap == null)
        {
            return null;
        }
        return this.subMap.get(key);
    }

    public Map<String, Data> unmodifiableSubMap()
    {
        if (this.subMap == null)
        {
            return Collections.emptyMap();
        }

        return Collections.unmodifiableMap(this.subMap);
    }

    /**
     * 列表替换.<br/>
     * @param items
     */
    public void setList(List<Map<String, Object>> items)
    {
        if (items == null || items.isEmpty())
        {
            return;
        }

        this.subList = new ArrayList<Map<String, Data>>(items.size());

        for (Map<String, Object> datas : items)
        {
            Map<String, Data> subs = new HashMap<String, Data>();
            java.util.Iterator<Entry<String, Object>> itr = datas.entrySet().iterator();
            for (; itr.hasNext();)
            {
                Entry<String, Object> entry = itr.next();
                subs.put(entry.getKey(), new Data(entry.getKey(), entry.getValue()));
            }
            this.subList.add(subs);
        }
        this.dataType = DataType.LIST;
    }

    /**
     * 列表替换.<br/>
     * @param items
     */
    public void setList(Data... items)
    {
        if (items == null || items.length == 0)
        {
            return;
        }

        this.subList = new ArrayList<Map<String, Data>>(items.length);
        for (Data data : items)
        {
            this.subList.add(data.getMap());
        }
        this.dataType = DataType.LIST;
    }

    /**
     * 将Data映射表作为列表中的一个元素.<br/>
     * @param datas
     */
    public void addMapItem(Map<String, Object> datas)
    {
        if (datas == null || datas.isEmpty())
        {
            return;
        }

        if (this.subList == null)
        {
            this.subList = new ArrayList<Map<String, Data>>(4);
            this.dataType = DataType.LIST;
        }

        Map<String, Data> subs = new HashMap<String, Data>();
        java.util.Iterator<Entry<String, Object>> itr = datas.entrySet().iterator();
        for (; itr.hasNext();)
        {
            Entry<String, Object> entry = itr.next();
            subs.put(entry.getKey(), new Data(entry.getKey(), entry.getValue()));
        }
        this.subList.add(subs);
        this.dataType = DataType.LIST;
    }

    /**
     * 将Data列表作为列表中的一个元素.<br/>
     * @param datas
     */
    public void addListItem(List<Data> datas)
    {
        if (datas == null || datas.isEmpty())
        {
            return;
        }

        if (this.subList == null)
        {
            this.subList = new ArrayList<Map<String, Data>>(4);
        }

        Map<String, Data> subs = new HashMap<String, Data>();
        for (Data data : datas)
        {
            subs.put(data.key(), data);
        }
        this.subList.add(subs);
        this.dataType = DataType.LIST;
    }

    public Data getListItem(int index)
    {
        if (this.subList == null || this.subList.isEmpty())
        {
            return null;
        }

        if (index < 0 || index >= this.subList.size())
        {
            return null;
        }
        /**
         * 重新包装一个Data对象
         */
        return new Data(this.key(), this.subList.get(index));
    }

    public int size()
    {
        return this.subMap.size();
    }

    public boolean isList()
    {
        return this.subList != null && this.subList.size() > 0;
    }

    public int listSize()
    {
        if (this.subList == null)
        {
            return -1;
        }

        return this.subList.size();
    }

    /**
     * 输出Json格式字符串
     * @see java.lang.Object#toString()
     */
    public String toString()
    {
        StringBuilder sb = new StringBuilder();
        sb.append(key).append(':');
        itemStringbuffer(sb, this);

        return sb.toString();
    }

    public static void itemStringbuffer(StringBuilder sb, Data data)
    {
        if (data.dataType() == DataType.PLAIN)
        {
            Object object = data.value();
            if (object instanceof Date)
            {
                sb.append('"');
                java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                sb.append(sdf.format((Date) object));
                sb.append('"');
            }
            else if (object instanceof Calendar)
            {
                sb.append('"');
                java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                sb.append(sdf.format(((Calendar) object).getTime()));
                sb.append('"');
            }
            else if (object instanceof Number)
            {
                sb.append(object);
            }
            else if (object instanceof CharSequence)
            {
                sb.append('"');
                sb.append(object);
                sb.append('"');
            }
            else if (object instanceof Character)
            {
                sb.append('"');
                sb.append(object);
                sb.append('"');
            }
            else
            {
                sb.append(object);
            }
        }
        else if (data.dataType() == DataType.LIST)
        {
            sb.append('[');
            toStringBuffer(sb, data.getSubList());
            sb.append(']');
        }
        else
        {
            sb.append('{');
            toStringBuffer(sb, data.getMap());
            sb.append('}');
        }
    }

    public static void toStringBuffer(StringBuilder sb, Map<String, Data> mapData)
    {
        for (Iterator<Entry<String, Data>> itr = mapData.entrySet().iterator(); itr.hasNext();)
        {
            Entry<String, Data> kv = itr.next();
            Data data = kv.getValue();
            sb.append(data.key).append(':');
            itemStringbuffer(sb, data);

            if (itr.hasNext())
            {
                sb.append(',');
            }
        }
    }

    public static void toStringBuffer(StringBuilder sb, List<Map<String, Data>> lstData)
    {
        for (Iterator<Map<String, Data>> itr = lstData.iterator(); itr.hasNext();)
        {
            Map<String, Data> data = itr.next();

            toStringBuffer(sb, data);

            if (itr.hasNext())
            {
                sb.append(',');
            }
        }
    }

    public static void main(String[] args)
    {
        Data base = new Data("Base");
        Data list = new Data("listSub");
        base.addSub(new Data("sub1", "DataSub1"));
        base.addSub(new Data("sub2", "DataSub2"));
        base.addSub(list);
        List<Data> listIndex1 = new ArrayList<Data>();
        listIndex1.add(new Data("itemKey1", "itemData1"));
        listIndex1.add(new Data("itemKey2", "itemData2"));
        list.addListItem(listIndex1);
        List<Data> listIndex2 = new ArrayList<Data>();
        listIndex2.add(new Data("itemKey1", "itemData1"));
        listIndex2.add(new Data("itemKey2", "itemData2"));
        listIndex2.add(new Data("itemKey3", 10000));
        listIndex2.add(new Data("itemKey4", 'A'));
        list.addListItem(listIndex2);

        System.out.println(base);
    }
}
